/****************************************************************************/
/*                                                                          */
/*   FILE:    link.c	                                                    */
/*   DATE:    25/06/97                                                      */
/*   PURPOSE: DVB-CI Link layer - entry point into LINK task          		*/
/*			- Initialization Module				    					    */
/*			- Main Module					    							*/
/*		    - Ending Module												    */
/*   TAB STOPS : 4															*/
/*   HISTORY:				                                    			*/
/*   Version	Date	  	    Written by	     Notes	    	   			*/
/*	 1.0	    25/06/1997      SCM              Initial implementation 	*/
/*	 1.04		31/07/1997		SCM         	 Acces to PHYSICAL Task		*/
/*								instead of PHYSICAL Driver					*/
/*   1.05       28/12/1998      SCM              In function LINK_AllocTcidIndex() */
/*                                            and function LINK_FreeSlotIndex() */
/*              changed "LINK_RazFifo()" to "LINK_ResetFifo()"				*/
/*                                                                   	    */
/*--------------------------------------------------------------------------*/
/*   GENERAL COMMENTS                                                 	    */
/*																		    */
/****************************************************************************/

#include <stdio.h>
#include "sm_trace.h"
#include "itc.h"
#include "link.h"


/*--------------------------------------------------------------------------*/
/* Global Variables		                                            		*/
/*--------------------------------------------------------------------------*/
lslot_t g_lnk_tab_slot[MAXSLOTID];/* slot table									*/
ltcid_t g_lnk_tab_tcid[MAXTCID];  /* tcid table   								*/
lnk_fifo_t	g_lnk_tab_fifo[MAXTCID];  /* fifo table									*/

/*--------------------------------------------------------------------------*/
/* External Variables		                                           		*/
/*--------------------------------------------------------------------------*/

/* ======================================================================== */
/* NAME : link								    							*/
/* 									    									*/
/* DESCRIPTION : entry point into LINK task :				    			*/
/*		 - Initialization Module				   							*/
/*		 - Main Module						    							*/
/*		 - Ending Module				         							*/
/*	The Main Module is an infinite loop :								    */
/*		 - wait events (messages from TRANS task or PHYSICAL Task		 	*/
/*		 - read the first received event  			   						*/
/*		 - call the LINK State Diagram LINK_State	  	        			*/
/*	                                                                  		*/
/* 									 										*/
/* INPUT PARAMETERS :							    						*/
/*									    									*/
/* OUTPUT PARAMETERS :							  							*/
/*									   										*/
/* RETURN CODE								   								*/
/*	 0    	 	success														*/
/*  -1			error														*/
/*									   										*/
/* ======================================================================== */
int link(void* param)
{
	int			rc = 0;
	xmsg_t		xmsg;

	SM_TRACE_CRITICAL(TRMOD_LINK, "link() - entry\r\n");

	/* Call the Initialization Module */
	if (! LINK_Init())
	{
		SM_TRACE_ERROR(TRMOD_LINK, "link() - LINK init failed\r\n");
		rc = -1; //error while Initialization
	}

	/* Main Module */
	/* =========== */
	while(rc == 0)		/* infinite loop */
	{
		/* Blocking Wait for event */
		SM_TRACE_INFO(TRMOD_LINK, "link() - wait for event infinite...\r\n");
		if (! ITC_RecvXmsg(&xmsg, ITC_INFINITE))
		{
			SM_TRACE_ERROR(TRMOD_LINK, "link() - LINK::Error in return code");
			rc = -1;
			break;
		}

		if (xmsg.m_type == XMG_EXIT)
		{
			SM_TRACE_CRITICAL(TRMOD_LINK, "link() - receive XMG_EXIT\r\n");
			break;
		}

		if (xmsg.m_type)
		{
			/* Call the link State Diagram */
			SM_TRACE_INFO(TRMOD_LINK, "link() - xmsg received\r\n");
			LINK_State(&xmsg);
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_LINK, "link() - received unknown xmsg=0x%02X\r\n", xmsg.m_type);
			rc = -1;
			break;
		}
	}

	/* Call the Ending Module : should never get executed */
	LINK_End();

	SM_TRACE_CRITICAL(TRMOD_LINK, "link() - return, rc=%d\r\n", rc);
	return rc;
}
/* End of Main Module */
/* ================== */


/* ======================================================================== */
/* NAME : LINK_Init							    							*/
/* 									    									*/
/* DESCRIPTION : Initialization Module					    				*/
/*		 link variables initialization			    						*/
/*		 link State Diagram initialization 	            					*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*	1   	 	successful initialization			   						*/
/*  0			error while initialization			    					*/
/*									   										*/
/* ======================================================================== */
int LINK_Init(void)
{
	int i;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Init() - entry\r\n");

	if (! ITC_Init(LINK))
		return 0;

	for (i=0; i < MAXSLOTID; i++)
	{
		g_lnk_tab_slot[i].m_state = LN_STAT_NOT_USED;
		g_lnk_tab_slot[i].m_slotId  = 0;
	}

	for (i=0; i < MAXTCID; i++)
	{
		g_lnk_tab_tcid[i].m_state = LN_STAT_NOT_USED;
		g_lnk_tab_tcid[i].m_slotId  = 0;
		g_lnk_tab_tcid[i].m_tcid  = 0;
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Init() - return\r\n");
	return 1;
}
/* End of Initialization Module */
/* ============================ */


/* ======================================================================== */
/* NAME : LINK_End							    							*/
/* 									    									*/
/* DESCRIPTION : Ending Module							    				*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*									   										*/
/* ======================================================================== */
void LINK_End(void)
{
	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_End() - entry\r\n");

	ITC_End();

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_End() - return\r\n");
	return;
}
/* End of Initialization Module */
/* ============================ */


/* ======================================================================== */
/* NAME : LINK_State													    */
/* 									    									*/
/* DESCRIPTION : Entry point of the link State Diagram Module				*/
/*		Read the event					       							    */
/*		Read the message							    				    */
/*		Find the current TCID and the matching state diagram index 			*/
/*		Call the current transition matches the received event	   			*/
/* 									   										*/
/* INPUT PARAMETERS :							   							*/
/*	g_lnk_tab_tcid[i].m_state gives the current state of the State Diagram  		*/
/*	for the current TCID (index i)					    					*/
/*									   										*/
/* OUTPUT PARAMETERS :							    						*/
/*	g_lnk_tab_tcid[i].m_state is updated					    					*/
/*									  										*/
/* RETURN CODE :							  							    */
/*									 									    */
/* ======================================================================== */
void LINK_State(xmsg_t* pXmsg)
{
	int iRet;			/* return code 		  		   */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_State() - entry\r\n");

	iRet = 0;

	SM_TRACE_INFO(TRMOD_LINK, "LINK_State() - received %s(0x%02X)\r\n",
					XMSG_NAME(pXmsg->m_type), pXmsg->m_type);
	switch (pXmsg->m_type)
	{
	case TPDU :			/* Link <--> Trans */
		iRet = LINK_Tpdu(pXmsg);
	    break;

	case LPDU :	    	/* Link <--> Physical */
		iRet = LINK_Lpdu(pXmsg);
		break;

	case LN_ACK :       /* Link <--- Physical */
		iRet = LINK_Ack(pXmsg);
		break;

	case LN_CONNECT :   /* Link <--- Physical */
		iRet = LINK_Connect(pXmsg);
		break;

	case LN_ERROR :     /* Link <--- Physical */
		iRet = LINK_Error(pXmsg);
		break;

	case LN_DISCONNECT :/* Link <--- Physical */
		iRet = LINK_Disconnect(pXmsg);
		break;

	default :			/* unknown message */
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_State() - ignore Unknown message 0x%02X\r\n", pXmsg->m_type);
		break;
	} //end switch

	FreeXmsg(pXmsg);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_State() - return\r\n");
}
/* End of link State Diagram */
/* ========================= */


/* ======================================================================== */
/* NAME : LINK_Connect						    							*/
/* 									    									*/
/* DESCRIPTION : LINK State Diagram : LN_CONNECT transition received 		*/
/*		- Create a new state diagram										*/
/*		- Call the action													*/
/*		- Update the state diagram											*/
/*									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_ln_connect contains the LN_CONNECT message received from PHYSICAL	*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*		g_lnk_tab_tcid[] updated												*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Connect(xmsg_t* pXmsg)
{
	int				lnkSlotIndex;	/* index of g_lnk_tab_tcid[] for the current module				*/
	unsigned short	slotId;	/* current slotId									*/

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Connect() - entry\r\n");

	if (pXmsg->m_bd.m_ln_connect.m_status == LN_OK)
	{
		SM_TRACE_INFO(TRMOD_LINK, "LINK_Connect() - will alloc new lnkSlotIndex for slotid=%d\r\n",
					pXmsg->m_bd.m_ln_connect.m_slotId);

		/* Add a new instance of the Link State Diagram for the new module					 			*/
		lnkSlotIndex = LINK_AllocSlotIndex(pXmsg);		/* get the new instance for the link state diagram 		*/
		if (lnkSlotIndex < 0)
		{
			SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connect() - alloc lnkSlotIndex failed\r\n");
			/* Send IHM_WARNING to IHM Task */
			return 0;	/* can't get new instance or module already connected, the request is ignored 	*/
	    }

		slotId = pXmsg->m_bd.m_ln_connect.m_slotId;
		SM_TRACE_INFO(TRMOD_LINK, "LINK_Connect() - alloc success,slotId=%d, lnkSlotIndex=%d\r\n",
				pXmsg->m_bd.m_ln_connect.m_slotId, lnkSlotIndex);

		/* Call the link state diagram */
		if (!LINK_Action(lnkSlotIndex, LN_CONNECT, 0, pXmsg))
		{
			SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connect() - LINK_Action failed, will free lnkSlotIndex\r\n");
			LINK_FreeSlotIndex(lnkSlotIndex, slotId);		/* error : free the new instance */
		}
    }
    else
    {	/* no DVB module, warning 		*/

		SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connect() - link connect status=0x%02X is error\r\n",
							pXmsg->m_bd.m_ln_connect.m_status);

		/* Send IHM_WARNING to IHM Task */
    }

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Connect() - return 1\r\n");
	return 1;
}


/* ======================================================================== */
/* NAME : LINK_Disconnect						    						*/
/* 									    									*/
/* DESCRIPTION : Link State diagram : LN_DISCONNECT received 				*/
/*		find the module														*/
/*		call the action														*/
/*		free the state diagram												*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_ln_disconn contains the LN_DISCONNECT message received from 		*/
/*		PHYSICAL Task	 													*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Disconnect(xmsg_t* pXmsg)
{
	int lnkSlotIndex;	/* index of g_lnk_tab_slot[] for the current module connection  	*/
	unsigned short slotId;	/* current slotId									*/

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Disconnect() - entry\r\n");

	lnkSlotIndex = LINK_GetSlotIndex(pXmsg->m_bd.m_ln_disconn.m_slotId);
	if (lnkSlotIndex >= 0)
	{	/* module found */
		slotId = pXmsg->m_bd.m_ln_disconn.m_slotId;

		LINK_Action(lnkSlotIndex, LN_DISCONNECT, 0, pXmsg);

		/* free the instance of state diagram and all associated tcid */
		LINK_FreeSlotIndex(lnkSlotIndex, slotId);
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Disconnect() - return 1\r\n");
	return 1;
}


/* ======================================================================== */
/* NAME : LINK_Error							    						*/
/* 									    									*/
/* DESCRIPTION : Link State diagram : LN_ERROR received 					*/
/*		find the module														*/
/*		call the action														*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_ln_error contains the LN_ERROR message received from PHYSICAL   */
/*		Task 																*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Error(xmsg_t* pXmsg)
{
	int lnkSlotIndex;		/* index of g_lnk_tab_slot[] for the current module connection */
	unsigned short slotId;	/* current slotId									*/

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Error() - entry\r\n");

	lnkSlotIndex = LINK_GetSlotIndex(pXmsg->m_bd.m_ln_error.m_slotId);
	if (lnkSlotIndex >= 0)
	{
		slotId = pXmsg->m_bd.m_ln_error.m_slotId;
		if (LINK_Action(lnkSlotIndex, LN_ERROR, (int)pXmsg->m_bd.m_ln_error.m_status, pXmsg))
			/* free the instance of state diagram and all associated tcid if the error is LN_PHYSICAL */
			LINK_FreeSlotIndex(lnkSlotIndex, slotId);
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Error() - return 1\r\n");
	return 1;
}


/* ======================================================================== */
/* NAME : LINK_Lpdu								    						*/
/* 									    									*/
/* DESCRIPTION : Link State diagram : LPDU received 						*/
/*		- Decod the LPDU													*/
/*		- Find the transport connection										*/
/*		- Call the action													*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_lpdu contains the LPDU message received from PHYSICAL Task	*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Lpdu(xmsg_t* pXmsg)
{
	int lnkSlotIndex;	/* index of g_lnk_tab_slot[] for the current module connection  	*/
	int tcidIndex;	/* index of g_lnk_tab_tcid[] for the current transport connection  */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Lpdu() - entry\r\n");

	lnkSlotIndex = LINK_GetSlotIndex(pXmsg->m_bd.m_lpdu.m_slotId);
	if (lnkSlotIndex >= 0)
	{   /* find the tcid coded in LPDU and his lnkSlotIndex into g_lnk_tab_tcid 		*/
	 	tcidIndex = LINK_GetTcidIndex(pXmsg->m_bd.m_lpdu.m_slotId, pXmsg->m_bd.m_lpdu.m_pbLpdu[0]);

	 	if (tcidIndex >= 0)
			LINK_Action(lnkSlotIndex, LPDU, tcidIndex, pXmsg);
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Lpdu() - return\r\n");
	return 0;
}


/* ======================================================================== */
/* NAME : LINK_Ack								    						*/
/* 									    									*/
/* DESCRIPTION : Link State diagram : LN_ACK received 						*/
/*		find the module														*/
/*		call the action														*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_ln_ack contains the LN_ACK message received from PHYSICAL Task  */
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Ack(xmsg_t* pXmsg)
{
	int lnkSlotIndex;		/* index of g_lnk_tab_slot[] for the current module connection  	*/
	int tcidIndex;	/* index of g_lnk_tab_tcid[] for the current transport connection  */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Ack() - entry\r\n");

	lnkSlotIndex = LINK_GetSlotIndex(pXmsg->m_bd.m_ln_ack.m_slotId);
	if (lnkSlotIndex >= 0)
	{   /* Get the current tcid saved in g_lnk_tab_slot and find his lnkSlotIndex			*/
	 	tcidIndex = LINK_GetTcidIndex(pXmsg->m_bd.m_ln_ack.m_slotId, g_lnk_tab_slot[lnkSlotIndex].m_tcid);
	 	if (tcidIndex >= 0)
			LINK_Action(lnkSlotIndex, LN_ACK, tcidIndex, pXmsg);
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Ack() - return 1\r\n");
	return 1;
}


/* ======================================================================== */
/* NAME : LINK_Tpdu							    							*/
/* 									    									*/
/* DESCRIPTION : Link State diagram : TPDU received 						*/
/*		- Find the module													*/
/*		- Find the transport connection										*/
/*		- If the tcid exists in g_lnk_tab_tcid, do nothing						*/
/*		- If the tcid don't exist in g_lnk_tab_tcid, create an entry into		*/
/*			g_lnk_tab_tcid since it's a new transport connection (create_t_c	*/
/*			sent by the TRANS task)											*/
/*		- Call the action													*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_bd.m_tpdu contains the TPDU message received from TRANS Task		*/
/*									    									*/
/* OUTPUT PARAMETERS :							    						*/
/*									    									*/
/* RETURN CODE :							    							*/
/*		0 : the calling function must free the memory containing the message*/
/*		1 : the calling function do nothing 								*/
/*									   										*/
/* ======================================================================== */
int LINK_Tpdu(xmsg_t* pXmsg)
{
	int lnkSlotIndex;		/* index of g_lnk_tab_slot[] for the current module connection  	*/
	int tcidIndex;	/* index of g_lnk_tab_tcid[] for the current transport connection  */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Tpdu() - entry\r\n");

	lnkSlotIndex = LINK_GetSlotIndex(pXmsg->m_bd.m_tpdu.m_slotId);
	if (lnkSlotIndex >= 0)
	{
		tcidIndex = LINK_GetTcidIndex(pXmsg->m_bd.m_tpdu.m_slotId, pXmsg->m_bd.m_tpdu.m_tcid);
		if (tcidIndex < 0)
		{
			SM_TRACE_INFO(TRMOD_LINK, "LINK_Tpdu() - will alloc new tcidindex for tcid=%d\r\n",
						pXmsg->m_bd.m_tpdu.m_tcid);

			/* create a new entry for a new transport connection */
			tcidIndex = LINK_AllocTcidIndex(lnkSlotIndex, pXmsg->m_bd.m_tpdu.m_slotId,
						pXmsg->m_bd.m_tpdu.m_tcid);
			if (tcidIndex < 0)
			{	/* no more available transport connection */
				/* Send IHM_WARNING to IHM Task */
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_Tpdu() - alloc new tcidindex for tcid=%d failed\r\n",
						pXmsg->m_bd.m_tpdu.m_tcid);
				return 0;
			}
			SM_TRACE_INFO(TRMOD_LINK, "LINK_Tpdu() - alloc new tcidindex for tcid=%d ok, tcidIndex=%d\r\n",
						pXmsg->m_bd.m_tpdu.m_tcid,tcidIndex);
		}
		/* Call the state diagram */
		LINK_Action(lnkSlotIndex, TPDU, tcidIndex, pXmsg);
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Tpdu() - return\r\n");
	return 0;
}



/* ======================================================================== */
/* NAME : LINK_GetSlotIndex					 									*/
/* 									    									*/
/* DESCRIPTION : Get the current entry in g_lnk_tab_slot						*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		slotId : slot identifier											*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : entry not found												*/
/*		>=0 : lnkSlotIndex in g_lnk_tab_slot											*/
/*									  										*/
/* ======================================================================== */
int LINK_GetSlotIndex(unsigned short slotId)
{
	int lnkSlotIndex;				/* return code : entry found */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_GetSlotIndex() - entry,slotId=%d\r\n", slotId);

	for (lnkSlotIndex=0; lnkSlotIndex < MAXSLOTID; lnkSlotIndex++)
	{
		if ((g_lnk_tab_slot[lnkSlotIndex].m_state != LN_STAT_NOT_USED)
			&& (g_lnk_tab_slot[lnkSlotIndex].m_slotId == slotId))
		{
			SM_TRACE_ENTRY(TRMOD_LINK, "LINK_GetSlotIndex() - slotId=%d found, lnkSlotIndex=%d\r\n",
						slotId, lnkSlotIndex);
			return lnkSlotIndex;	/* entry found 	   */
		}
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_GetSlotIndex() - return, slotId=%d not found, return -1\r\n", slotId);
	return -1;				/* entry not found */
}


/* ======================================================================== */
/* NAME : LINK_GetTcidIndex					 									*/
/* 									    									*/
/* DESCRIPTION : Get the current entry in g_lnk_tab_tcid						*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		slotId : slot identifier												*/
/*		tcid : transport connection identifier								*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : entry not found												*/
/*		>=0 : tidIndex in g_lnk_tab_tcid											*/
/*									  										*/
/* ======================================================================== */
int LINK_GetTcidIndex(unsigned short slotId, unsigned char tcid)
{
	int tidIndex;				/* return code : entry found */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_GetTcidIndex() - entry,slotId=%d, tcid=%d\r\n",slotId,tcid);
	for (tidIndex=0; tidIndex < MAXTCID; tidIndex++)
	{
		if ((g_lnk_tab_tcid[tidIndex].m_state != LN_STAT_NOT_USED) &&
			(g_lnk_tab_tcid[tidIndex].m_slotId == slotId)
			&& (g_lnk_tab_tcid[tidIndex].m_tcid == tcid))
		{
			SM_TRACE_INFO(TRMOD_LINK, "LINK_GetTcidIndex() - slotId=%d, tcid=%d found, tidIndex=%d\r\n",
							slotId,tcid,tidIndex);
			return tidIndex;	/* entry found 	   */
		}
	}

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_GetTcidIndex() - return, slotId=%d, tcid=%d not found\r\n",slotId,tcid);
	return -1;				/* entry not found */
}



/* ======================================================================== */
/* NAME : LINK_AllocTcidIndex					 									*/
/* 									    									*/
/* DESCRIPTION : Reserve a new entry in g_lnk_tab_tcid							*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex: index in g_lnk_tab_slot											*/
/*		slotId : slot identifier												*/
/*		tcid : transport connection identifier								*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*		update the number of tcid for the current slot						*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : no more free entry 											*/
/*		>=0 : index in g_lnk_tab_tcid											*/
/*									  										*/
/* ======================================================================== */
int LINK_AllocTcidIndex(int lnkSlotIndex, unsigned short slotId, unsigned char tcid)
{
	int tcidIndex;			/* return code : entry found */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_AllocTcidIndex() - entry,lnkSlotIndex=%d,slotId=%d,tcid=%d\r\n",
					lnkSlotIndex,slotId,tcid);

	for (tcidIndex=0; tcidIndex < MAXTCID; tcidIndex++)
	{
		if (g_lnk_tab_tcid[tcidIndex].m_state == LN_STAT_NOT_USED)
		{
			g_lnk_tab_tcid[tcidIndex].m_tcid  = tcid;
			g_lnk_tab_tcid[tcidIndex].m_slotId  = slotId;
			g_lnk_tab_tcid[tcidIndex].m_state = LN_STAT_CONNECTED;

			LINK_ResetFifo(tcidIndex);		/* Reset Fifo for incoming TPDU*/

			g_lnk_tab_slot[lnkSlotIndex].m_tcidCount++;	/* one more tcid for this slot */

			SM_TRACE_INFO(TRMOD_LINK, "LINK_AllocTcidIndex() - alloc new entry ok, tcid=%d,tcidIndex=%d\r\n",
						tcid, tcidIndex);
			return tcidIndex;	/* entry found 	   */
		}
	}

	SM_TRACE_ERROR(TRMOD_LINK, "LINK_AllocTcidIndex() - no more entry for tcid=%d\r\n", tcid);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_AllocTcidIndex() - return -1\r\n");
	return -1;					/* entry not found */
}



/* ======================================================================== */
/* NAME : LINK_AllocSlotIndex					 									*/
/* 									    									*/
/* DESCRIPTION : Get a new entry in g_lnk_tab_slot								*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		pXmsg->m_msg.m_body points the received informations								*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*		g_lnk_tab_slot is updated												*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : no more entry													*/
/*		 -2 : already connected												*/
/*		 -3 : wrong physical buffer size									*/
/*		>=0 : lnkSlotIndex in g_lnk_tab_slot											*/
/*									  										*/
/* ======================================================================== */
int LINK_AllocSlotIndex(xmsg_t* pXmsg)
{
	int lnkSlotIndex;				/* return code : entry found */

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_AllocSlotIndex() - entry, slotId=%d\r\n",
				pXmsg->m_bd.m_ln_connect.m_slotId);

	for (lnkSlotIndex=0; lnkSlotIndex < MAXSLOTID; lnkSlotIndex++)
	{
		if (g_lnk_tab_slot[lnkSlotIndex].m_state == LN_STAT_NOT_USED)   /* take the first free entry, reserve it */
		{
        	if ((pXmsg->m_bd.m_ln_connect.m_negoSize < MIN_LPDU_SIZE)
					|| (pXmsg->m_bd.m_ln_connect.m_negoSize > MAX_LPDU_SIZE))
        	{
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_AllocSlotIndex() - wrong physical buffer size %d\r\n",
								pXmsg->m_bd.m_ln_connect.m_negoSize);
				return -3;
        	}
        	else
        	{
				g_lnk_tab_slot[lnkSlotIndex].m_slotId = pXmsg->m_bd.m_ln_connect.m_slotId;
				g_lnk_tab_slot[lnkSlotIndex].m_state   = LN_STAT_IDLE;
				g_lnk_tab_slot[lnkSlotIndex].m_tcidCount  = 0;
				g_lnk_tab_slot[lnkSlotIndex].m_isTpduSending    = 0;

				g_lnk_tab_slot[lnkSlotIndex].m_negoSize = pXmsg->m_bd.m_ln_connect.m_negoSize;

				SM_TRACE_INFO(TRMOD_LINK, "LINK_AllocSlotIndex() - alloc lnkSlotIndex=%d success with slotId=%d\r\n",
							lnkSlotIndex, pXmsg->m_bd.m_ln_connect.m_slotId);
				return lnkSlotIndex;
			}
		}
		else
		{
			if (g_lnk_tab_tcid[lnkSlotIndex].m_slotId == pXmsg->m_bd.m_ln_connect.m_slotId)
			{
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_AllocSlotIndex() - slot already connected\r\n");
				return -2;	/* slot already connected */
			}
		}
    }

	SM_TRACE_ERROR(TRMOD_LINK, "LINK_AllocSlotIndex() - no more entry\r\n");
	SM_TRACE_RETURN(TRMOD_LINK, "LINK_AllocSlotIndex() - return -1\r\n");
	return -1;				/* no more entry */
}


/* ======================================================================== */
/* NAME : LINK_FreeSlotIndex					 								*/
/* 									    									*/
/* DESCRIPTION :Delete an entry in g_lnk_tab_slot and all tcid entries in 		*/
/*				g_lnk_tab_tcid													*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex : index of the entry to delete								*/
/*		slotId  : slot identifier												*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*									    									*/
/* RETURN CODE								    							*/
/*		< 0 : entry not found												*/
/*		>=0 : entry deleted													*/
/*									  										*/
/* ======================================================================== */
int LINK_FreeSlotIndex(int lnkSlotIndex, unsigned short slotId)
{
	int tcidIndex;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_FreeSlotIndex() - entry,lnkSlotIndex=%d, slotId=%d\r\n",
				lnkSlotIndex, slotId);

    if ((lnkSlotIndex < 0) && (lnkSlotIndex >= MAXSLOTID))
	{
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_FreeSlotIndex() - invalid lnkSlotIndex=%d\r\n", lnkSlotIndex);
    	return -1;
	}

	g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_NOT_USED;				/* free the entry 	*/
	g_lnk_tab_slot[lnkSlotIndex].m_slotId  = 0;

	/* Look for all tcid entries and release them */
	for (tcidIndex=0; tcidIndex < MAXTCID; tcidIndex++)
	{
		if (g_lnk_tab_tcid[tcidIndex].m_slotId == slotId)
		{
			g_lnk_tab_tcid[tcidIndex].m_tcid  = 0;
			g_lnk_tab_tcid[tcidIndex].m_slotId  = 0;
			g_lnk_tab_tcid[tcidIndex].m_state = LN_STAT_NOT_USED;

			LINK_ResetFifo(tcidIndex);				/* Reset Fifo for incoming TPDU	*/
		}
	 }

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_FreeSlotIndex() - return,lnkSlotIndex=%d\r\n", lnkSlotIndex);
	return lnkSlotIndex;
}




